package com.tutucms.service.admin.service;

import com.tutucms.common.exception.ValidateException;
import com.tutucms.common.security.AESUtil;
import com.tutucms.common.security.ImageVerCodeUtil;
import com.tutucms.common.util.BeanFiller;
import com.tutucms.common.util.CharUtil;
import com.tutucms.repo.entity.User;
import com.tutucms.repo.mapper.UserMapper;
import com.tutucms.service.admin.common.UserContext;
import com.tutucms.service.admin.model.ro.LoginRo;
import com.tutucms.service.admin.model.vo.UserVo;
import com.tutucms.service.common.SessionHolder;
import com.tutucms.service.model.consts.Const;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * Created by wangxudong on 2020/10/29.
 *
 * @version: 1.0
 * @modified :
 */
@Slf4j
@Service
public class AuthService {

    // 16位
    private static final String PIC_CAPTCHA_SECRET_KEY = "captcha2tu2image";

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserContext userContext;

    public String login(LoginRo ro) {

        vertPicCaptcha(ro.getPicCaptcha());

        // 验证用户
        User example = new User();
        example.setUserName(ro.getUserName());
        example.setPassword(ro.getPassword());

        List<User> users = userMapper.select(example);

        if (CollectionUtils.isEmpty(users)) {
            throw new ValidateException("用户名或密码错误");
        }

        return userContext.login(users.get(0));
    }

    public void captchaImage(HttpServletResponse response) throws IOException {

        String captcha = new ImageVerCodeUtil().generateVerifyCode(4);
        // 生成sessionId,并使用AES加密，过期时间10分钟
        String sessionId = AESUtil.encrypt(captcha + ":" + (System.currentTimeMillis() + 600000), PIC_CAPTCHA_SECRET_KEY);
        Cookie cookie = new Cookie(Const.CAPTCHA_SESSION_NAME, sessionId);
        cookie.setPath("/");
        cookie.setMaxAge(0);
        response.addCookie(cookie);
        response.addHeader(Const.CAPTCHA_SESSION_NAME, sessionId);
        response.addHeader("Access-Control-Expose-Headers", "*");
        SessionHolder.getSession().setAttribute(Const.CAPTCHA_SESSION_NAME, sessionId);
        new ImageVerCodeUtil().outputImage(200, 50, response.getOutputStream(), captcha);
    }

    public UserVo getCurrentUser() {

        User user = userContext.getUser();

        if (user == null) {

            return null;
        }
        user.setPassword("");

        return BeanFiller.target(UserVo.class).accept(user);
    }

    /**
     * 验证图片验证码
     * @param captchaCode
     */
    private void vertPicCaptcha(String captchaCode) {
        String sessionId = null;
        // 验证图片验证码
        Cookie[] cookies = SessionHolder.getRequest().getCookies();
        if (cookies != null) {
            sessionId = Arrays.stream(cookies)
                    .filter(c -> c.getName().equals(Const.CAPTCHA_SESSION_NAME)).map(Cookie::getValue).findFirst().orElse(null);
        }
        if (CharUtil.isEmpty(sessionId)) {
            sessionId = SessionHolder.getRequest().getHeader(Const.CAPTCHA_SESSION_NAME);
            if (CharUtil.isEmpty(sessionId)) {
                sessionId = (String) SessionHolder.getSession().getAttribute(Const.CAPTCHA_SESSION_NAME);
            }
        }
        if (CharUtil.isEmpty(sessionId)) {
            throw new ValidateException("验证码错误");
        }
        String decrypt = AESUtil.decrypt(sessionId, PIC_CAPTCHA_SECRET_KEY);
        if (decrypt == null) {
            throw new ValidateException("验证码错误");
        }
        String[] decrypts = decrypt.split(":");
        String captcha = decrypts[0];
        Long expiration = CharUtil.stringParsLong(decrypts[1]);
        if (!Objects.equals(captchaCode.toUpperCase(), captcha.toUpperCase())
                || expiration == null || expiration <= System.currentTimeMillis()) {
            throw new ValidateException("验证码错误");
        }
    }
}
